home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 019a / tde10src.zip / TDEASM.C < prev    next >
C/C++ Source or Header  |  1991-06-05  |  40KB  |  983 lines

  1. /*
  2.  * I have decided to use ^Z to mark the begin and end of files instead of '\0'.
  3.  * That way, null characters are allowed as normal text characters.  ^Z is used
  4.  * to mark the end of strings in buffers instead of '\0'.  The standard C
  5.  * string library functions should not be used when dealing with text buffers.
  6.  *
  7.  * The often used string routines have been rewritten in assembly.  When using
  8.  * 16 bit processors, accessing memory by WORDs on WORD boundaries is twice
  9.  * as fast as accessing memory by BYTEs.  If a memory pointer is even then it
  10.  * is WORD aligned.  If a memory pointer is odd, do the first BYTE and then
  11.  * the rest of the string is WORD aligned on an even boundary.
  12.  *
  13.  * Two routines were written to adjust the string pointers whenever they
  14.  * approach the end of a segment.  With these two routines, the code may
  15.  * be compiled without the huge memory model.  Another assembly routine was
  16.  * written to compare physical memory locations.  For example, all of these
  17.  * pointers point to same physical memory address:
  18.  *
  19.  *         59a1:9122 == 58a1:a122 == 62a1:0122  = physical address 404,274
  20.  *
  21.  * An efficient way to compare far pointers is to convert them to either
  22.  * unsigned long or long integers.  Either one will do - their is no such
  23.  * thing a negative physical memory address.  A long int goes from
  24.  * -2 billion to 2 billion, which leaves plenty of room to describe a physical
  25.  * address, using a long, where the max is 1 MEG.  I used unsigned long.  When
  26.  * adding or subtracting from the physical address of a pointer, we should
  27.  * never, ever get a negative physical address.  This is the concept behind the
  28.  * function ptoul, which is short for pointer to unsigned long.
  29.  *
  30.  * With these functions written in assembly, this editor is fairly fast.  I
  31.  * feel the need for speed.
  32.  *
  33.  * New editor name:  tde, the Thomson-Davis Editor.
  34.  * Author:           Frank Davis
  35.  * Date:             June 5, 1991
  36.  *
  37.  * This modification of Douglas Thomson's code is released into the
  38.  * public domain, Frank Davis.  You may distribute it freely.
  39.  */
  40.  
  41. #include "tdestr.h"
  42. #include "common.h"
  43. #include "tdefunc.h"
  44.  
  45. /*
  46.  * Name:    cpf - check_pointer_foward
  47.  * Purpose: To adjust a pointer if it is nearing end of a segment (within 16k)
  48.  * Date:    June 5, 1991
  49.  * Passed:  s:  string pointer
  50.  * Notes:   To avoid a bunch of code generated for pointer arithmetic when using
  51.  *          the huge memory model, this routine adjusts a pointer when it
  52.  *          approaches the end of a segment.
  53.  */
  54. text_ptr cpf( s )
  55. text_ptr s;
  56. {
  57.    _asm {
  58.         mov     ax, WORD PTR s  ; get offset of s
  59.         mov     dx, WORD PTR s+2        ; get segment of s
  60.         cmp     ax, 0xc000      ; are we within 16k of top of segment?
  61.         jb      get_out         ; no, get out
  62.         sub     ax, 0x8000      ; yes, subtract 32k from offset
  63.         add     dx, 0x0800      ; add 0x0800 paragraphs to segment == 32k
  64. get_out:
  65.    }
  66. }
  67.  
  68. /*
  69.  * Name:    cpb - check_pointer_backward
  70.  * Purpose: To adjust a pointer if it is nearing beginning of a segment (16k)
  71.  * Date:    June 5, 1991
  72.  * Passed:  s:  string pointer
  73.  * Notes:   To avoid a bunch of code generated for pointer arithmetic when using
  74.  *          the huge memory model, this routine adjusts a pointer when it
  75.  *          approaches the beginning of a segment.  Don't check NULL pointer.
  76.  */
  77. text_ptr cpb( s )
  78. text_ptr s;
  79. {
  80.    _asm {
  81.         mov     ax, WORD PTR s  ; get offset of s
  82.         mov     dx, WORD PTR s+2        ; get segment of s
  83.         cmp     ax, 0           ; is offset of s == NULL?
  84.         jne     not_null        ; no, check pointer
  85.         cmp     dx, 0           ; is segment of s == NULL?
  86.         je      get_out         ; yes, don't check NULL pointer
  87. not_null:
  88.         cmp     ax, 0x4000      ; are we within 16k of beginning of segment?
  89.         jae     get_out         ; no, get out
  90.         add     ax, 0x8000      ; yes, add 32k to offset
  91.         sub     dx, 0x0800      ; sub 0x0800 paragraphs from segment == 32k
  92. get_out:
  93.    }
  94. }
  95.  
  96. /*
  97.  * Name:    ptoul - pointer to unsigned long
  98.  * Purpose: convert a far pointer to unsigned long integer
  99.  * Date:    June 5, 1991
  100.  * Passed:  s:  string pointer
  101.  * Notes:   combine the offset and segment like so:
  102.  *                offset       0000
  103.  *                segment   + 0000
  104.  *                          =======
  105.  *                            00000
  106.  *          result is returned in ax:dx
  107.  */
  108. unsigned long ptoul( s )
  109. text_ptr s;
  110. {
  111.    _asm {
  112.         mov     ax, WORD PTR s          ; ax = offset of s
  113.         mov     dx, WORD PTR s+2        ; dx = segment of s
  114.         mov     bx, dx          ; put copy of segment in bx
  115.         mov     cl, 12          ; cl = decimal 12 - shift hi word 3 digits
  116.         shr     dx, cl          ; convert to 'real segment'
  117.         mov     cl, 4           ; cl = 4  - shift hi word 1 digit
  118.         shl     bx, cl          ; shift bx - line up on paragraph
  119.         add     ax, bx          ; add low part of segment to offset
  120.         adc     dx, 0           ; if carry, bump to next 'real' segment
  121.    }
  122. }
  123.  
  124.  
  125. /*
  126.  * Name:    addltop - add long to pointer
  127.  * Purpose: add long integer to a pointer
  128.  * Date:    June 5, 1991
  129.  * Passed:  l: long
  130.  *          p: text pointer
  131.  * Returns: pointer + long integer
  132.  * Notes:   A long integer takes two WORDs.  A far pointer takes two WORDs.
  133.  *          A long integer cannot be added directly to a far pointer.
  134.  *              This diagram may help explain better than I can write.
  135.  *
  136.  *          far pointer            0000   offset
  137.  *                                0xxx    segment
  138.  *                                  +
  139.  *          long integer       00000000             -throw away those three
  140.  *                                ======             digits on long integer,
  141.  *                                 0000   offset     they have no effect
  142.  *           new far pointer      0xxx    segment
  143.  *
  144.  *          msw = Most Significant WORD
  145.  *          lsw = Least Significant WORD
  146.  *
  147.  *          When working with the long integer, we don't need to worry about
  148.  *          the three x's on segment of the pointer.  Add or subtract the lsw
  149.  *          of the long integer to/from the offset.  If there is a carry,
  150.  *          it only affects the left most digit of the msw of the pointer.
  151.  */
  152. text_ptr addltop( l, p )
  153. long l;
  154. text_ptr p;
  155. {
  156.  
  157.    if (l >= 0) {
  158.       _asm {
  159.         mov     ax, WORD PTR p          ; ax = offset of p
  160.         mov     dx, WORD PTR p+2        ; dx = segment of p
  161.         mov     bx, WORD PTR l+2        ; msw of l in bx
  162.         add     ax, WORD PTR l          ; add lsw of p and lsw of l
  163.         adc     bx, 0                   ; if carry, pointer in another segment
  164.         mov     cl, 12                  ; cl = 12 - shift off 3 digits
  165.         shl     bx, cl                  ; only handle 1st part of msw of l
  166.         add     dx, bx                  ; add msw of p and msw of l
  167.       }
  168.    } else {
  169.       l = -l;      /* convert l to positive and subtract from pointer p */
  170.       _asm {
  171.         mov     ax, WORD PTR p          ; ax = offset of p
  172.         mov     dx, WORD PTR p+2        ; dx = segment of p
  173.         mov     bx, WORD PTR l+2        ; msw of l in bx
  174.         mov     cl, 12                  ; cl = 12 - shift off 3 digits
  175.         sub     ax, WORD PTR l          ; subtract low part of pointer
  176.         adc     bx, 0                   ; if we borrowed then add it back to bx
  177.         shl     bx, cl                  ; only handle 1st digit of msw of l
  178.         sub     dx, bx                  ; subtract msw from segment of p
  179.       }
  180.    }
  181. }
  182.  
  183.  
  184. /*
  185.  * Name:    find_CONTROL_Z - assembler version, see commented C at end
  186.  * Purpose: To determine the length of a line up to ^Z
  187.  * Date:    June 5, 1991
  188.  * Passed:  s: the line to be measured
  189.  * Notes:   DOS carried over ^Z to mark the end of files from CP/M.  Since
  190.  *          it is the only character not allowed in regular text files.  ^Z
  191.  *          can be used, instead of '\0', to mark the end of strings.  All
  192.  *          ASCII characters, except ^Z, may be included in a text file.
  193.  *          However, none of the C string library functions should be used
  194.  *          when working with text.  The string library functions can be used
  195.  *          on responses solicited from the user.
  196.  * Returns: the length of the line
  197.  */
  198. int  find_CONTROL_Z( s )
  199. text_ptr s;
  200. {
  201.    s = cpf( s );
  202.    _asm {
  203.         mov     dx, ds          ; keep ds in dx, MUST save data segment
  204.         push    si              ; put copy of si on stack
  205.  
  206.         xor     cx, cx          ; cx = 0
  207.         mov     si, WORD PTR s  ; put offset of s in si
  208.         mov     ax, WORD PTR s+2        ; get segment of s
  209.         mov     ds, ax          ; else, segment in ds
  210.         cmp     si, 0           ; is offset of s == NULL?
  211.         jne     not_null        ; no, find length
  212.         cmp     ax, 0           ; is segment of s == NULL?
  213.         je      get_out         ; yes, line length = 0
  214. not_null:
  215.         mov     bl, CONTROL_Z   ; keep Control Z in bl - eos marker
  216.         mov     ax, si          ; pointer is ok, check for word align
  217.         shr     ax, 1           ; if [si] is odd, lsb is 1 - rotate to carry
  218.         jnc     top             ; see if string is WORD aligned
  219.         lodsb                   ; no, get a BYTE - now WORD aligned
  220.         cmp     al, bl          ; is ds:[si] == ^Z?
  221.         je      get_out         ; yes, have length, cx = 0
  222.         inc     cx              ; increment length variable
  223.         ALIGN   2
  224. top:
  225.         lodsw                   ; string is WORD aligned
  226.         cmp     al, bl          ; is lo BYTE == ^Z?
  227.         je      get_out         ; yes, we have length
  228.         inc     cx              ; no, increment counter
  229.         cmp     ah, bl          ; now test higher BYTE, is it ^Z?
  230.         je      get_out         ; yes, we have length
  231.         inc     cx              ; no, increment length
  232.         jmp     SHORT top       ; look at next two characters
  233. get_out:
  234.         mov     ax, cx          ; put length in ax - as defined by Microsoft
  235.         mov     ds, dx          ; get back data segment from dx
  236.         pop     si              ; get back si from stack
  237.    }
  238.  
  239. /*
  240. int len = 0;
  241.  
  242.    while (*s != ^Z) {
  243.       ++len;
  244.       ++s;
  245.    }
  246.    return len;
  247. */
  248. }
  249.  
  250.  
  251. /*
  252.  * Name:    linelen - assembler version, see commented C at end of routine
  253.  * Purpose: To determine the length of a line, up to either a \n or a
  254.  *           ^Z, whichever comes first.
  255.  * Date:    June 5, 1991
  256.  * Passed:  s: the line to be measured
  257.  * Notes:   Demonstrates 'lodsb' and 'lodsw'.  Memory operations are most
  258.  *           efficient when working with WORDs.  See if first BYTE in
  259.  *           string is WORD aligned.  If it is then work with WORDs else
  260.  *           get the first BYTE and rest of string will be WORD aligned.
  261.  *           The 'mov' instruction could have been used, but 'lobsb' and
  262.  *           'lodsw' automatically increment the memory pointer.
  263.  * Returns: the length of the line
  264.  */
  265. int  linelen( s )
  266. text_ptr s;
  267. {
  268.    s = cpf( s );
  269.    _asm {
  270.         mov     dx, ds          ; keep ds in dx, MUST save data segment
  271.         push    si              ; save si on stack
  272.  
  273.         xor     cx, cx          ; cx = 0
  274.         mov     si, WORD PTR s  ; put offset of s in si
  275.         mov     ax, WORD PTR s+2        ; get segment of s
  276.         mov     ds, ax          ; else, segment in ds
  277.         cmp     si, 0           ; is offset of s == NULL?
  278.         jne     not_null        ; no, find length
  279.         cmp     ax, 0           ; is segment of s == NULL?
  280.         je      get_out         ; yes, line length = 0
  281. not_null:
  282.         mov     bl, '\n'        ; keep new line character in bl
  283.         mov     bh, CONTROL_Z   ; keep Control Z in bh - DOS eof marker
  284.         mov     ax, si          ; pointer is ok, check for word align
  285.         shr     ax, 1           ; if [si] is odd, lsb is 1 - rotate to carry
  286.         jnc     top             ; see if string is WORD aligned
  287.         lodsb                   ; no, get a BYTE - now WORD aligned
  288.         cmp     al, bl          ; is BYTE == '\n'?
  289.         je      get_out         ; yes, have length, cx = 0
  290.         cmp     al, bh          ; is ds:[si] == ^Z?
  291.         je      get_out         ; yes, have length, cx = 0
  292.         inc     cx              ; increment length variable
  293.         ALIGN   2
  294. top:
  295.         lodsw                   ; string is WORD aligned
  296.         cmp     al, bl          ; test lower BYTE, is it '\n'
  297.         je      get_out         ; yes, we have length
  298.         cmp     al, bh          ; no, test for ^Z
  299.         je      get_out         ; yes, we have length
  300.         inc     cx              ; no, increment counter
  301.         cmp     ah, bl          ; now test higher BYTE, is it '\n'
  302.         je      get_out         ; yes, we have length
  303.         cmp     ah, bh          ; is it ^Z
  304.         je      get_out         ; yes, we have length
  305.         inc     cx              ; no, increment length
  306.         jmp     SHORT top       ; look at next two characters
  307. get_out:
  308.         mov     ax, cx          ; put length in ax - as defined by Microsoft
  309.         mov     ds, dx          ; get back data segment from dx
  310.         pop     si              ; get back si from stack
  311.    }
  312.  
  313. /*
  314. int len = 0;
  315.  
  316.    while (*s && *s != '\n') {
  317.       ++len;
  318.       ++s;
  319.    }
  320.    return len;
  321. */
  322. }
  323.  
  324. /*
  325.  * Name:    prelinelen
  326.  * Purpose: To determine the length of a line, from the current position
  327.  *           backwards to either a \n or a ^Z, whichever comes first.
  328.  * Date:    June 5, 1991
  329.  * Passed:  s: the line to be measured
  330.  * Returns: the length of the line up to the current position
  331.  * Notes:   It is assumed there will be a "terminating" ^Z before the
  332.  *           start of the first line.
  333.  */
  334. int prelinelen( s )
  335. text_ptr s;
  336. {
  337.    s = cpb( s );
  338.    _asm {
  339.         push    di              ; put copy of di on stack
  340.  
  341.         xor     ax, ax          ; ax = 0, keep string length in ax
  342.         mov     di, WORD PTR s  ; get offset of string
  343.         mov     dx, WORD PTR s+2        ; get segment of string
  344.         mov     es, dx          ; put segment in es
  345.         cmp     di, 0           ; is offset of string == NULL?
  346.         jne     not_null        ; no, do string stuff
  347.         cmp     dx, 0           ; is, segment of string == NULL?
  348.         je      get_out         ; yes, don't do NULL string
  349. not_null:
  350.         dec     di              ; look at previous character
  351. ALWORD: dec     di              ; get ready to chech for WORD align
  352.         mov     bl, '\n'        ; keep '\n' in bl
  353.         mov     bh, CONTROL_Z   ; keep ^Z in bh
  354.         mov     dx, di          ; pointer is ok, check for WORD align
  355.         shr     dx, 1           ; if [di] is odd, lsb is 1 - rotate to carry
  356.         jnc     top             ; string is WORD aligned
  357.         inc     di              ; fix the second decrement - see ALWORD
  358.         mov     dl, BYTE PTR es:[di]    ; get a BYTE - put in DL
  359.         cmp     dl, bl          ; is it '\n'
  360.         je      get_out         ; yes, get out - count = 0
  361.         cmp     dl, bh          ; is it ^Z
  362.         je      get_out         ; yes, get out - count = 0
  363.         inc     ax              ; increment length counter
  364.         dec     di              ; pointer was BYTE aligned, dec pointer
  365.         dec     di              ; pointer is now WORD aligned
  366.         ALIGN   2
  367. top:
  368.         mov     dx, WORD PTR es:[di]    ; load WORD - hi BYTE is next
  369.         cmp     dh, bl          ; is hi BYTE (next char) '\n'?
  370.         je      get_out         ; yes, get out - count already in ax
  371.         cmp     dh, bh          ; is hi BYTE (next char) ^Z?
  372.         je      get_out         ; yes, get out - count already in ax
  373.         inc     ax              ; increment character counter
  374.         cmp     dl, bl          ; now check lo BYTE, is it '\n'?
  375.         je      get_out         ; yes, get out - count is in ax
  376.         cmp     dl, bh          ; is lo BYTE ^Z?
  377.         je      get_out         ; yes, get out - count is in ax
  378.         inc     ax              ; increment character counter
  379.         dec     di              ; decrement pointer
  380.         dec     di              ; align pointer on WORD
  381.         jmp     SHORT top       ; test next 2 characters
  382. get_out:
  383.         pop     di              ; get back di from stack
  384.    }
  385. /*
  386. int len = 0;
  387.  
  388.    while (*--s != CONTROL_Z && *s != '\n')
  389.       ++len;
  390.    return len;
  391. */
  392. }
  393.  
  394. /*
  395.  * Name:    find_next
  396.  * Purpose: To find the first character in the next line after the starting
  397.  *           point.
  398.  * Date:    June 5, 1991
  399.  * Passed:  s: the starting point
  400.  * Returns: the first character in the next line
  401.  * Notes:   This function goes faster if machine works with WORDs.  See if
  402.  *           first BYTE in string is WORD aligned.  If it is not, get first
  403.  *           BYTE in string then the rest of string is WORD aligned.
  404.  *           Code added at end to adjust segment:offset if needed.
  405.  */
  406. text_ptr find_next( s )
  407. text_ptr s;
  408. {
  409.    _asm {
  410.         push    ds              ; save ds on stack
  411.         push    si              ; save si on stack
  412.  
  413.         mov     si, WORD PTR s          ; load offset of s
  414.         mov     ax, WORD PTR s+2        ; load segment of s
  415.         mov     ds, ax
  416.         cmp     si, 0           ; is offset of string == NULL?
  417.         jne     not_null        ; no, do string stuff
  418.         cmp     ax, 0           ; is segment of string == NULL?
  419.         je      return_null     ; yes, return NULL if string is NULL
  420. not_null:
  421.         mov     bl, '\n'        ; keep '\n' in bl
  422.         mov     bh, CONTROL_Z   ; keep ^Z in bh
  423.         mov     ax, si          ; move offset of si to ax
  424.         shr     ax, 1           ; shift right into carry flag
  425.         jnc     top             ; is string WORD aligned?
  426.         lodsb                   ; no, get a BYTE
  427.         cmp     al, bl          ; is it '\n'?
  428.         je      next_even       ; yes, si alread incremented by lodsb
  429.         cmp     al, bh          ; is it ^Z?
  430.         je      return_null     ; yes, return NULL
  431.         ALIGN   2
  432. top:
  433.         lodsw                   ; string is WORD aligned, get two BYTEs
  434.         cmp     al, bl          ; is next BYTE == '\n'?
  435.         je      next_odd        ; yes, since si inc for WORD (lodsw) - dec di
  436.         cmp     al, bh          ; is next BYTE == ^Z?
  437.         je      return_null     ; yes, return NULL
  438.         cmp     ah, bl          ; is next BYTE in AH == '\n'?
  439.         je      next_even       ; yes, si is OK - return pointer to next BYTE
  440.         cmp     ah, bh          ; is next BYTE in AH == ^Z?
  441.         je      return_null     ; yes, return NULL
  442.         jmp     SHORT top       ; look at next WORD
  443.         ALIGN   2
  444. return_null:
  445.         xor     ax, ax          ; clear ax - offset = NULL
  446.         xor     dx, dx          ; clear dx - segment = NULL
  447.         jmp     SHORT get_out   ; return text_ptr in dx:ax - see Microsoft
  448.         ALIGN   2
  449. next_odd:
  450.         dec     si              ; 'lodsw' went one BYTE too far - so dec si
  451. next_even:
  452.         mov     ax, si          ; ds:si now points to next line, load ax
  453.         mov     dx, ds          ; load dx with segment of next BYTE
  454.         cmp     ax, 0xc000      ; are we within 16k of segment?
  455.         jb      get_out         ; no, get out
  456.         sub     ax, 0x8000      ; yes, subtract 32k from offset
  457.         add     dx, 0x0800      ; add 0x0800 paragraphs to segment
  458. get_out:
  459.         pop     si              ; get back si from stack
  460.         pop     ds              ; get back ds from stack
  461.    }
  462. /*
  463.    while (*s && *s != '\n')
  464.       ++s;
  465.    if (*s)
  466.       return ++s;
  467.    else
  468.       return NULL;
  469. */
  470. }
  471.  
  472. /*
  473.  * Name:    find_prev
  474.  * Purpose: To find the start of the line before the current line.
  475.  * Date:    June 5, 1991
  476.  * Passed:  current: the current line
  477.  * Returns: the start if the previous line
  478.  * Notes:   current must be at the start of the current line to begin with.
  479.  *          There must be a ^Z preceding the first line.
  480.  *          This function goes faster if machine works with WORDs.  See if
  481.  *           first BYTE in string is WORD aligned.  If it is not, get first
  482.  *           BYTE in string then the rest of string is WORD aligned.
  483.  *           The test for '\n' will pass a lot more than the test for
  484.  *           ^Z.  Set up the WORD align stuff first.
  485.  *           Since we are searching, by WORDs, backwards, the hi BYTE is the
  486.  *           prev BYTE and the al BYTE is two prev BYTEs (make sense?).
  487.  *           Code added at end to adjust segment:offset if needed.
  488.  */
  489. text_ptr find_prev( current )
  490. text_ptr current;
  491. {
  492.    _asm {
  493.         push    di              ; save di on stack
  494.  
  495.         mov     di, WORD PTR current    ; load offset of current
  496. DECR1:  dec     di                      ; decrement it
  497.         mov     ax, WORD PTR current+2  ; load segment of current
  498.         mov     es, ax
  499.         cmp     di, 0           ; is offset of string == NULL?
  500.         jne     not_null        ; no, do string string stuff
  501.         cmp     ax, 0           ; is segment of string == NULL?
  502.         je      return_null     ; yes, return NULL if string NULL
  503. not_null:
  504.         mov     bl, '\n'        ; keep '\n' in bl
  505.         mov     bh, CONTROL_Z   ; keep ^Z in bh
  506.         mov     ax, di          ; put copy of offset in ax
  507.         shr     ax, 1           ; shift right thru carry flag
  508.         jnc     on_boundary     ; if no carry, string is WORD aligned
  509. ;
  510. ; if we were to dec the pointer twice, it would be WORD aligned with the
  511. ; '--current'  BYTE in the AH register.  if ^Z test fails, might as well
  512. ; test the BYTE in the AL register.
  513. ;
  514. DECR2:  dec     di              ; dec offset one more so it is WORD aligned
  515.         mov     ax, WORD PTR es:[di]    ; might as well load WORD
  516.         cmp     ah, bh          ; is prev BYTE ^Z?
  517.         je      return_null     ; yes, return NULL
  518. ;
  519. ; now we are in the for loop - see commented C code at bottom.
  520. ; 'on_boundary' is not part of the for loop so jump past it if needed.
  521. ;
  522.         cmp     al, bl          ; is prev BYTE '\n'?
  523.         je      inc_pointer     ; yes, increment the pointer and return
  524.         cmp     al, bh          ; is it ^Z?
  525.         je      inc_pointer     ; yes, increment the pointer and return
  526.         jmp     SHORT for_loop  ;no, pointer is now WORD aligned - do for loop
  527.         ALIGN   2
  528. ;
  529. ; the string ended on an odd boundary and the DECR1 has now aligned the
  530. ; string on a WORD.  if we load a WORD, the '--current' BYTE would be in the
  531. ; AL register.
  532. ;
  533. on_boundary:
  534.         mov     ax, WORD PTR es:[di]    ; load --current, aligned on WORD
  535.         cmp     al, bh          ; is --current ^Z?
  536.         je      return_null     ; yes, return NULL
  537. ;
  538. ; now we are in the for loop and string is guaranteed WORD aligned.
  539. ; IMPORTANT: there are 2 cases if the test for '\n' or ^Z pass.
  540. ;            1) AH passed, so di must be increment twice for '++current'
  541. ;            2) AL passed, inc di once for '++current'
  542. ;
  543.         ALIGN   2
  544. for_loop:
  545.         dec     di              ; decrement di twice so it will be
  546.         dec     di              ; WORD aligned
  547.         mov     ax, WORD PTR es:[di]    ; string is WORD aligned
  548.         cmp     ah, bl          ; is --current '\n'?
  549.         je      next_even       ; yes, increment di twice to return ++current
  550.         cmp     ah, bh          ; is --current ^Z?
  551.         je      next_even       ; yes, increment di twice to return ++current
  552.         cmp     al, bl          ; look at low part of WORD, is it '\n'?
  553.         je      inc_pointer     ; yes, increment di once to return ++current
  554.         cmp     al, bh          ; is low part of WORD ^Z?
  555.         je      inc_pointer     ; yes, increment di once to return ++current
  556.         jmp     SHORT for_loop  ; get next WORD
  557.         ALIGN   2
  558. return_null:
  559.         xor     ax, ax          ; clear ax - offset = NULL
  560.         xor     dx, dx          ; clear dx - segment = NULL
  561.         jmp     SHORT get_out   ; return text_ptr in dx:ax - see Microsoft
  562.         ALIGN   2
  563. next_even:
  564.         inc     di              ; di is a WORD too far - inc di
  565. inc_pointer:
  566.         inc     di              ; ++current
  567.         mov     ax, di          ; put offset in ax
  568.         mov     dx, es          ; put segment in dx, return dx:ax - Microsoft
  569.         cmp     ax, 0x4000      ; are we within 16k of segment?
  570.         jae     get_out         ; no, get out
  571.         add     ax, 0x8000      ; yes, add 32k to offset
  572.         sub     dx, 0x0800      ; sub 0x0800 paragraphs to segment
  573. get_out:
  574.         pop     di              ; get back di from stack
  575.    }
  576.  
  577. /*
  578.    if (*--current == ^Z)
  579.       return NULL;
  580.    for (;;) {
  581.       if (*--current == '\n' || *current == ^Z)
  582.          return ++current;
  583.    }
  584. */
  585. }
  586.  
  587. /*
  588.  * Name:    update_line
  589.  * Purpose: Display the current line in window
  590.  * Date:    June 5, 1991
  591.  * Passed:  window:   information allowing access to the current window
  592.  * Returns: none
  593.  * Notes:   Show string starting at column zero and if needed blank rest
  594.  *           of line.  Put max_col in cx and count down.  When we run into
  595.  *           '\n', cx contains number of columns to blank out.  Use the
  596.  *           fast 'rep stosw' to clear the end of line.
  597.  */
  598. void update_line( window )
  599. windows *window;
  600. {
  601. text_ptr text;      /* current character of orig begin considered */
  602. char far *screen_ptr;
  603. int attr;
  604. int line;
  605. int col;
  606. int bc, ec;
  607. int normal, block;
  608. int max_col;
  609. int block_line;
  610. int len;
  611. int c;
  612. long rline;
  613. file_infos *file;
  614.  
  615.    file = window->file_info;
  616.    max_col = g_display.ncols;
  617.    line = window->cline;
  618.    normal = g_display.text_color;
  619.    block = g_display.block_color;
  620.          /* 160 = 80 chars + 80 attr  for each line */
  621.    screen_ptr = g_display.display_address + line * 160;
  622.    text = cpf( window->cursor );
  623.    bc = window->bcol;
  624.    if (bc > 0) {
  625.       if ((col = linelen( text )) < bc)
  626.          bc = col;
  627.       text += bc;
  628.    }
  629.    rline = window->rline;
  630.    if (file->block_type && rline >= file->block_br && rline <= file->block_er)
  631.       block_line = TRUE;
  632.    else
  633.       block_line = FALSE;
  634.    if (block_line == TRUE && file->block_type == BLOCK) {
  635.       len = linelen( text );
  636.       bc = file->block_bc - window->bcol;
  637.       ec = file->block_ec - window->bcol;
  638.  
  639.       _asm {
  640.         push    ds                      ; MUST save ds - push it on stack
  641.         push    si                      ; save si on stack
  642. ;
  643. ; set up local register variables
  644. ;
  645.         mov     ax, WORD PTR bc         ; get beginning column
  646.         mov     bl, al                  ; keep it in bl
  647.         mov     ax, WORD PTR ec         ; get ending column
  648.         mov     bh, al                  ; keep it in bh
  649.         mov     ax, WORD PTR normal     ; get normal attribute
  650.         mov     dl, al                  ; keep it in dl
  651.         mov     ax, WORD PTR block      ; get block attribute
  652.         mov     dh, al                  ; keep it in dh
  653.         mov     ax, WORD PTR max_col    ; get max number columns on screen
  654.         mov     ch, al                  ; keep it in ch
  655.         xor     cl, cl                  ; col = 0, keep col in cl
  656. ;
  657. ; load screen and text pointer
  658. ;
  659.         mov     di, WORD PTR screen_ptr         ; load offset of screen ptr
  660.         mov     ax, WORD PTR screen_ptr+2       ; load segment of screen ptr
  661.         mov     es, ax
  662.         mov     si, WORD PTR text       ; load offset of text ptr
  663.         mov     ax, WORD PTR text+2     ; load segment of text ptr
  664.         mov     ds, ax                  ; move segment of text in ds
  665.         cmp     si, 0                   ; is offset of text ptr == NULL?
  666.         jne     not_null                ; no, output string
  667.         cmp     ax, 0                   ; is segment of text ptr == NULL?
  668.         je      block_eol               ; yes, clear end of line
  669. not_null:
  670.         ALIGN   2
  671. top:
  672.         cmp     cl, ch          ; is col == max_col 0?
  673.         je      getout          ; yes, thru with line
  674.         lodsb                   ; get next char in string
  675.         cmp     al, CONTROL_Z   ; is it ^Z?
  676.         je      block_eol       ; yes, must check block past ^Z
  677.         cmp     al, '\n'        ; is it '\n'?
  678.         je      block_eol       ; yes, must check block past '\n'
  679.         mov     ah, dl          ; assume normal attribute
  680.         cmp     cl, bl          ; is col < bc? (less than beginning col)
  681.         jl      ch_out1         ; yes, show char and normal attribute
  682.         cmp     cl, bh          ; is col > ec? (greater than ending col)
  683.         jg      ch_out1         ; yes, show char and normal attribute
  684.         mov     ah, dh          ; must be in a block - show block attribute
  685. ch_out1:
  686.         stosw                   ; else show char on screen
  687.         inc     cl              ; ++col
  688.         jmp     SHORT top       ; get another character
  689.         ALIGN   2
  690. block_eol:
  691.         mov     al, ' '         ; clear rest of line w/ spaces
  692. b1:
  693.         mov     ah, dl          ; assume normal attribute
  694.         cmp     cl, bl          ; is col < bc? (less than beginning col)
  695.         jl      ch_out2         ; yes, show char and normal attribute
  696.         cmp     cl, bh          ; is col > ec? (greater than ending col)
  697.         jg      ch_out2         ; yes, show char and normal attribute
  698.         mov     ah, dh          ; must be in a block - show block attribute
  699. ch_out2:
  700.         stosw                   ; write blank and attribute to screen
  701.         inc     cl              ; ++col
  702.         cmp     cl, ch          ; is col == max_col?
  703.         jl      b1              ; while less output block
  704. getout:
  705.         pop     si
  706.         pop     ds
  707.       }
  708. /*
  709.       for (col=0; col < max_col; col++) {
  710.          attr = normal;
  711.          if (col >= bc && col <= ec)
  712.             attr = block;
  713.          if (col < len)
  714.             c = text[col];
  715.          else
  716.             c = ' ';
  717.          update_char( c, col, line, attr );
  718.       }
  719. */
  720.    } else {
  721.       if (block_line)
  722.          attr = block;
  723.       else
  724.          attr = normal;
  725.       _asm {
  726.         mov     dx, ds          ; MUST save ds - keep it in dx
  727.         push    di              ; save di on stack
  728.         push    si              ; save si on stack
  729.  
  730.         mov     bx, WORD PTR attr               ; keep attribute in bl
  731.         mov     bh, '\n'                        ; keep '\n' in bh
  732.         mov     cx, WORD PTR max_col            ; keep max_col in cx
  733.         mov     di, WORD PTR screen_ptr         ; load offset of screen ptr
  734.         mov     ax, WORD PTR screen_ptr+2       ; load segment of screen ptr
  735.         mov     es, ax
  736.         mov     si, WORD PTR text       ; load offset of text ptr
  737.         mov     ax, WORD PTR text+2     ; load segment of text ptr
  738.         mov     ds, ax                  ; move segment of text in ds
  739.         cmp     si, 0                   ; is offset of pointer == NULL?
  740.         jne     nnot_null               ; no, output string
  741.         cmp     ax, 0                   ; is segment of pointer == NULL?
  742.         je      clreol                  ; yes, then clear rest of line
  743. nnot_null:
  744.         mov     ah, bl                  ; get attribute
  745.         ALIGN   2
  746. topp:
  747.         or      cx, cx          ; col == 0 ?
  748.         je      getoutt         ; yes, thru with line
  749.         lodsb                   ; get next char in string
  750.         cmp     al, CONTROL_Z   ; is it ^Z
  751.         je      clreol          ; yes, clear end of line
  752.         cmp     al, bh          ; is it '\n'
  753.         je      clreol          ; yes, clear end of line
  754.         stosw                   ; else show char on screen
  755.         dec     cx              ; --col, count down from max_column
  756.         jmp     SHORT topp      ; get another character
  757.         ALIGN   2
  758. clreol:
  759.         mov     ah, bl          ; get attribute
  760.         mov     al, ' '         ; clear eol with ' '
  761.         rep     stosw           ; count is in cx - set rest of line to ' '
  762. getoutt:
  763.         pop     si
  764.         pop     di
  765.         mov     ds, dx
  766.       }
  767.    }
  768. /*
  769.    if (orig != NULL) {
  770.       text = orig;
  771.       screen_ptr = g_display.display_address + line * 160 + col * 2;
  772.       for (; *text != '\n' && *text != ^Z && col < max_col; text++, col++) {
  773.          *screen_ptr++ = *text;
  774.          *screen_ptr++ = attr;
  775.       }
  776.    }
  777.    if (col < max_col)
  778.       eol_clear( col, line, attr );
  779. */
  780. }
  781.  
  782.  
  783. /*
  784.  * Name:    update_char
  785.  * Purpose: diplay one character in window
  786.  * Date:    June 5, 1991
  787.  * Passed:  window:  information allowing access to the current window
  788.  *          c:  character to output to screen
  789.  *          col:  col to display character
  790.  *          line:  line number to display character
  791.  * Returns: none
  792.  */
  793. void update_char( window, c, col, line )
  794. windows *window;
  795. int c, col, line;
  796. {
  797. char far *screen_ptr;
  798. int attr;
  799. long rline;
  800. file_infos *file;
  801.  
  802.    file = window->file_info;
  803.    rline = window->rline;
  804.    attr = g_display.text_color;
  805.    if (file->block_type) {
  806.       if (rline >= file->block_br && rline <= file->block_er) {
  807.          if (file->block_type == LINE)
  808.             attr = g_display.block_color;
  809.          else if (window->rcol>=file->block_bc && window->rcol<=file->block_ec)
  810.             attr = g_display.block_color;
  811.       }
  812.    }
  813.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  814.  
  815.    _asm {
  816.         mov     dx, di                  ; save di in dx
  817.  
  818.         mov     di, WORD PTR screen_ptr         ; load offset of screen ptr
  819.         mov     ax, WORD PTR screen_ptr+2       ; load segment of screen ptr
  820.         mov     es, ax
  821.         mov     bx, WORD PTR attr       ; get attribute
  822.         mov     ah, bl                  ; put in ah
  823.         mov     bx, WORD PTR c          ; get character
  824.         mov     al, bl                  ; put in al
  825.         stosw                           ; show char on screen
  826.  
  827.         mov     di, dx                  ; get back di from dx
  828.    }
  829.  
  830. /*
  831.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  832.    *screen_ptr++ = c;
  833.    *screen_ptr = attr;
  834. */
  835. }
  836.  
  837.  
  838. /*
  839.  * Name:    c_output
  840.  * Purpose: To make as few changes as possible to cause the current line
  841.  *           to be what it should be.
  842.  * Date:    June 5, 1991
  843.  * Passed:  c:     character to output to screen
  844.  *          col:   col to display character
  845.  *          line:  line number to display character
  846.  *          attr:  attribute of character
  847.  * Returns: none
  848.  */
  849. void c_output( c, col, line, attr )
  850. int c, col, line, attr;
  851. {
  852. char far *screen_ptr;
  853.  
  854.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  855.  
  856.    _asm {
  857.         mov     dx, di                  ; save di in dx
  858.  
  859.         mov     di, WORD PTR screen_ptr         ; load offset of screen ptr
  860.         mov     ax, WORD PTR screen_ptr+2       ; load segment of screen ptr
  861.         mov     es, ax
  862.         mov     bx, WORD PTR attr       ; get attribute
  863.         mov     ah, bl                  ; put in ah
  864.         mov     bx, WORD PTR c          ; get character
  865.         mov     al, bl                  ; put in al
  866.         stosw                           ; show char on screen
  867.  
  868.         mov     di, dx                  ; get back di from dx
  869.    }
  870.  
  871. /*
  872.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  873.    *screen_ptr++ = c;
  874.    *screen_ptr = attr;
  875. */
  876. }
  877.  
  878.  
  879. /*
  880.  * Name:    s_output
  881.  * Purpose: To output character string at the cursor position, advancing
  882.  *           the cursor by the length of the string.
  883.  * Date:    June 5, 1991
  884.  * Passed:  s: string to output
  885.  * Notes:   This function is used to output most strings not part of file text.
  886.  */
  887. void s_output( s, line, col, attr )
  888. char *s;
  889. int line, col, attr;
  890. {
  891. text_ptr text;      /* current character of orig begin considered */
  892. char far *screen_ptr;
  893. int max_col;
  894.  
  895.    max_col = g_display.ncols;
  896.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  897.  
  898.    _asm {
  899.         push    ds              ; MUST save ds
  900.         push    di              ; save di on stack
  901.         push    si              ; save si on stack
  902.  
  903.         mov     bx, WORD PTR attr               ; keep attribute in bx
  904.         mov     cx, WORD PTR col                ; put cols in cx
  905.         mov     dx, WORD PTR max_col            ; keep max_col in dx
  906.         mov     di, WORD PTR screen_ptr         ; load offset of screen ptr
  907.         mov     ax, WORD PTR screen_ptr+2       ; load segment of screen ptr
  908.         mov     es, ax
  909.         mov     si, WORD PTR s  ; load offset of string ptr
  910.         or      si, si          ; is it == NULL?
  911.         je      getout          ; yes, no output needed
  912.         mov     ax, WORD PTR s+2        ; load segment of string ptr
  913.         or      ax, ax          ; is pointer == NULL?
  914.         je      getout          ; yes, no output needed
  915.         mov     ds, ax          ; load segment of text in ds
  916.         mov     ah, bl          ; put attribute in AH
  917. top:
  918.         cmp     cx, dx          ; col < max_cols?
  919.         jge     getout          ; no, thru with line
  920.         lodsb                   ; get next char in string - put in al
  921.         or      al, al          ; is it '\0'
  922.         je      getout          ; yes, end of string
  923.         stosw                   ; else show attr + char on screen (ah + al)
  924.         inc     cx              ; col++
  925.         jmp     SHORT top       ; get another character
  926. getout:
  927.         pop     si              ; get back si
  928.         pop     di              ; get back di
  929.         pop     ds              ; get back ds
  930.    }
  931.  
  932. /*
  933.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  934.    max_col = g_display.ncols;
  935.    while (*s && col < max) {
  936.       *screen_ptr++ = *s++;
  937.       *screen_ptr++ = attr;
  938.    }
  939. */
  940. }
  941.  
  942. /*
  943.  * Name:    eol_clear
  944.  * Purpose: To clear the current line from the cursor to the end of the
  945.  *           line to normal spaces.
  946.  * Date:    June 5, 1991
  947.  * Notes:   Basic assembly - comments should be enough explanation.
  948.  */
  949. void eol_clear( int col, int line, int attr )
  950. {
  951. int max_col;
  952. char far *screen_ptr;
  953.  
  954.    max_col = g_display.ncols;
  955.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  956.  
  957.    _asm {
  958.         push    di                              ; save di on stack
  959.  
  960.         mov     bx, WORD PTR attr               ; keep attribute in bx
  961.         mov     dx, WORD PTR col                ; put cols in dx
  962.         mov     cx, WORD PTR max_col            ; put max_col in cx
  963.         cmp     dx, cx                          ; max_cols < cols?
  964.         jge     getout                          ; no, thru with line
  965.         sub     cx, dx                          ; number of column to clear
  966.         mov     di, WORD PTR screen_ptr         ; load offset of screen ptr
  967.         mov     ax, WORD PTR screen_ptr+2       ; load segment of screen ptr
  968.         mov     es, ax
  969.         mov     ah, bl                          ; get attribute in ah
  970.         mov     al, ' '                         ; store ' ' in al
  971.         rep     stosw                           ; clear to end of line
  972. getout:
  973.         pop     di                              ; get back di from stack
  974.    }
  975.  
  976. /*
  977.    for (; col < g_display.ncols; col++) {
  978.       *p++ = ' ';
  979.       *p++ = attr;
  980.    }
  981. */
  982. }
  983.